#!/usr/bin/env node

// IPTV直播源爬虫 - 专为北京联通IPv6环境优化
// 每周一零点自动执行，筛选可用直播源并同步到Gitee

// 直播源列表URL
const SOURCE_URLS = [
  "https://gh-proxy.com/https://raw.githubusercontent.com/vbskycn/iptv/refs/heads/master/tv/iptv6.txt",
  "https://gh-proxy.com/https://raw.githubusercontent.com/vbskycn/iptv/refs/heads/master/tv/iptv4.txt",
  "https://gh.tryxd.cn/raw.githubusercontent.com/Guovin/iptv-api/gd/output/result.m3u",
  "https://gh.tryxd.cn/raw.githubusercontent.com/suxuang/myIPTV/main/ipv4.m3u",
   //"https://live.izbds.com/tv/iptv6.txt",
   //"http://aktv.space/live.m3u",
   // 可以添加更多直播源
  "https://raw.githubusercontent.com/fanmingming/live/main/tv/m3u/ipv6.m3u"
];

// Gitee仓库信息
const GITEE_REPO = "https://gitee.com/syysmq/iptv-live";
const OUTPUT_FILE = "ipv6.m3u";

// 导入所需模块
const fetch = require("node-fetch");
const { exec } = require("child_process");
const fs = require("fs").promises;
const path = require("path");

// 频道优先级排序规则
const CHANNEL_PRIORITY = {
  "CCTV": 1,
  "北京": 2,
  "卫视": 3,
  "其他": 4
};

/**
 * 验证URL是否可访问
 * @param {string} url - 需要验证的URL
 * @returns {Promise<boolean>} - URL是否可访问
 */
async function verifyUrl(url) {
  try {
    const controller = new AbortController();
    const timeoutId = setTimeout(() => controller.abort(), 5000);
    
    const res = await fetch(url, {
      method: "GET",
      headers: {
        "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:122.0) Gecko/20100101 Firefox/122.0"
      },
      signal: controller.signal
    });
    
    clearTimeout(timeoutId);
    return res.ok;
  } catch (e) {
    console.log(`验证URL失败: ${url}`);
    return false;
  }
}

/**
 * 执行命令行命令
 * @param {string} cmd - 要执行的命令
 * @returns {Promise<[Error, string, string]>} - 命令执行结果
 */
async function execCommand(cmd) {
  return new Promise((resolve) => {
    exec(cmd, (err, stdout, stderr) => {
      resolve([err, stdout, stderr]);
    });
  });
}

/**
 * 获取URL内容
 * @param {string} url - 要获取内容的URL
 * @returns {Promise<string>} - URL内容
 */
async function getUrlContent(url) {
  try {
    const response = await fetch(url, {
      headers: {
        "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:122.0) Gecko/20100101 Firefox/122.0"
      },
      timeout: 10000
    });
    
    if (!response.ok) {
      throw new Error(`获取内容失败: ${response.status}`);
    }
    
    return await response.text();
  } catch (e) {
    console.log(`获取URL内容失败: ${url}`, e.message);
    return "";
  }
}

/**
 * 解析M3U格式的内容
 * @param {string} content - M3U格式内容
 * @returns {Array} - 解析后的频道列表
 */
function parseM3U(content) {
  const lines = content.split(/\r?\n/);
  const channels = [];
  let currentChannel = null;
  
  for (let i = 0; i < lines.length; i++) {
    const line = lines[i].trim();
    
    if (line.startsWith('#EXTINF:')) {
      // 解析频道信息行
      currentChannel = {
        info: line,
        url: "",
        title: "",
        group: ""
      };
      
      // 提取频道名称
      const titleMatch = line.match(/,(.*)$/);
      if (titleMatch && titleMatch[1]) {
        currentChannel.title = titleMatch[1].trim();
      }
      
      // 提取分组信息
      const groupMatch = line.match(/group-title="([^"]*)"/i);
      if (groupMatch && groupMatch[1]) {
        currentChannel.group = groupMatch[1];
      }
    } else if (line.startsWith('http') && currentChannel) {
      // 这是频道URL行
      currentChannel.url = line;
      channels.push(currentChannel);
      currentChannel = null;
    }
  }
  
  return channels;
}

/**
 * 解析传统格式的直播源内容
 * @param {string} content - 传统格式内容
 * @returns {Array} - 解析后的频道列表
 */
function parseTraditionalFormat(content) {
  const lines = content.split(/\r?\n/);
  const channels = [];
  let currentGroup = "未分类";
  
  for (const line of lines) {
    const trimmedLine = line.trim();
    if (!trimmedLine) continue;
    
    if (trimmedLine.includes("#genre#")) {
      // 这是分组行
      currentGroup = trimmedLine.replace(/,#genre#/, "").trim();
    } else {
      // 这是频道行
      const parts = trimmedLine.split(",");
      if (parts.length >= 2) {
        const title = parts[0].trim();
        const url = parts[1].trim();
        
        if (url.startsWith('http')) {
          channels.push({
            title: title,
            url: url,
            group: currentGroup,
            info: `#EXTINF:-1 group-title="${currentGroup}",${title}`
          });
        }
      }
    }
  }
  
  return channels;
}

/**
 * 获取频道的优先级
 * @param {Object} channel - 频道对象
 * @returns {number} - 频道优先级
 */
function getChannelPriority(channel) {
  const title = channel.title.toUpperCase();
  
  if (title.includes('CCTV') && title.includes('高清')) {
    return 1;
  } else if (title.includes('CCTV')) {
    return 1.5;
  } else if (title.includes('北京') && title.includes('高清')) {
    return 2;
  } else if (title.includes('北京')) {
    return 2.5;
  } else if (title.includes('卫视') && title.includes('高清')) {
    return 3;
  } else if (title.includes('卫视')) {
    return 3.5;
  }
  
  return 4;
}

/**
 * 检查频道是否符合筛选条件
 * @param {Object} channel - 频道对象
 * @returns {boolean} - 是否符合条件
 */
function isChannelAllowed(channel) {
  // 获取tvg-name值
  const tvgNameMatch = channel.info.match(/tvg-name="([^"]*)"/i);
  const tvgName = tvgNameMatch ? tvgNameMatch[1].toLowerCase() : '';
  
  // 如果没有tvg-name，则使用title
  const nameToCheck = tvgName || channel.title.toLowerCase();
  
  // 检查是否包含cctv、北京或卫视关键字
  return nameToCheck.includes('cctv') || 
         nameToCheck.includes('北京') || 
         nameToCheck.includes('卫视');
}

/**
 * 将频道列表转换为M3U格式
 * @param {Array} channels - 频道列表
 * @returns {string} - M3U格式内容
 */
function convertToM3U(channels) {
  // 筛选符合条件的频道
  const filteredChannels = channels.filter(isChannelAllowed);
  console.log(`筛选后保留 ${filteredChannels.length} 个频道（仅CCTV、北京和卫视）`);
  
  // 按优先级排序频道
  filteredChannels.sort((a, b) => {
    const priorityA = getChannelPriority(a);
    const priorityB = getChannelPriority(b);
    
    if (priorityA !== priorityB) {
      return priorityA - priorityB;
    }
    
    // 同优先级按名称排序
    return a.title.localeCompare(b.title, 'zh-CN');
  });
  
  // 生成M3U内容
  let m3uContent = '#EXTM3U x-tvg-url="https://live.fanmingming.com/e.xml"\n';
  
  for (const channel of filteredChannels) {
    // 处理频道名称以提取正确的logo
    let logoName = channel.title.replace(/(CCTV|CETV)-(\d+).*/, "$1$2");
    
    // 构建EXTINF行
    let infoLine = `#EXTINF:-1 tvg-name="${logoName}" tvg-logo="https://live.fanmingming.com/tv/${logoName}.png"`;
    
    if (channel.group) {
      infoLine += ` group-title="${channel.group}"`;
    }
    
    infoLine += `,${channel.title}`;
    
    m3uContent += infoLine + '\n' + channel.url + '\n';
  }
  
  return m3uContent;
}

/**
 * 提交更改到Gitee仓库
 * @returns {Promise<boolean>} - 是否成功提交
 */
async function pushToGitee() {
  try {
    console.log("正在提交更改到Gitee...");
    
    // 添加文件到暂存区
    const [addErr] = await execCommand("git add .");
    if (addErr) {
      console.error("Git add 失败:", addErr);
      return false;
    }
    
    // 提交更改
    const date = new Date().toISOString();
    const [commitErr] = await execCommand(`git commit -m "自动更新IPTV直播源: ${date}"`);
    if (commitErr && !commitErr.message.includes("nothing to commit")) {
      console.error("Git commit 失败:", commitErr);
      return false;
    }
    
    // 推送到远程仓库
    const [pushErr] = await execCommand("git push origin master");
    if (pushErr) {
      console.error("Git push 失败:", pushErr);
      return false;
    }
    
    console.log("成功提交更改到Gitee!");
    return true;
  } catch (error) {
    console.error("提交到Gitee时出错:", error);
    return false;
  }
}

/**
 * 主函数 - 爬取并处理IPTV直播源
 */
async function main() {
  console.log("开始爬取IPTV直播源...");
  
  // 存储所有有效频道
  const allChannels = [];
  
  // 从所有源获取内容
  for (const url of SOURCE_URLS) {
    console.log(`正在处理源: ${url}`);
    const content = await getUrlContent(url);
    
    if (!content) {
      console.log(`无法获取内容: ${url}`);
      continue;
    }
    
    // 根据内容格式解析频道
    let channels = [];
    if (content.includes('#EXTM3U')) {
      channels = parseM3U(content);
    } else {
      channels = parseTraditionalFormat(content);
    }
    
    console.log(`从 ${url} 解析到 ${channels.length} 个频道`);
    
    // 验证频道URL是否可访问
    for (const channel of channels) {
      if (await verifyUrl(channel.url)) {
        allChannels.push(channel);
        console.log(`有效频道: ${channel.title}`);
      } else {
        console.log(`无效频道: ${channel.title}`);
      }
    }
  }
  
  console.log(`总共找到 ${allChannels.length} 个有效频道`);
  
  // 转换为M3U格式并保存
  const m3uContent = convertToM3U(allChannels);
  await fs.writeFile(OUTPUT_FILE, m3uContent, 'utf8');
  console.log(`已保存到 ${OUTPUT_FILE}`);
  
  // 提交到Gitee
  await pushToGitee();
  
  console.log("任务完成!");
}

// 执行主函数
main().catch(error => {
  console.error("程序执行出错:", error);
  process.exit(1);
});